类和对象 一、面向过程和面向对象 1 2 3 4 5 6 7 1. 编程: 特定的语法+数据结构+算法组成一段代码告诉计算机如何执行一个任务的过程(程序:数据结构+算法)2. 编程范式:条条大路通罗马,实现一个任务可以有很多种不同的方式(范式有很多种),不同的编程范式本质上来说就是对各种不同类型的任务采取的不同解决问题的思路3. 编程范式分类: 两种编程的方式 - 面向过程的编程:C语言 - 面向对象的编程:C++、Java、Python
1、面向过程编程
实现一个任务是自上而下的设计方式,程序从上到下一步步执行,从头到尾来解决问题
获取用户输入的数据、对数据进行运算并做出某种决策、在屏幕显示计算结果
根据业务逻辑从上到下垒代码
函数式编程 :在面向过程的编程中,也可以使用函数式编程 – 将某个功能模块的代码封装到一个函数中,之后便可以重复地去调用这个函数。
2、面向对象编程 OOP
对数据和函数进行分类和封装,让开发‘更快更好更强….’ – 更高层次的一种封装
面向对象编程,更抽象、封装性更好
需求(产品经理):计算坐标系中两点间距离
1 2 3 4 5 6 7 8 9 10 # 1.面向过程: 一步步进行,过程化 1. 输入数据x1,y1 = int(input('x1:')),int(input('y1:')) x2,y2 = int(input('x2:')),int(input('y2:')) 2. 运算、计算distance = ((x1-x2)**2+(y1-y2)** 2)**0.5 3. 输出结果 print(f'({x1},{y1})和({x2},{y2})之间的距离为:{distance}')
1 2 3 4 5 6 7 8 9 10 11 # 2.函数式编程:模块化、封装化 def distance(**kwargs): x1 = kwargs.get('x1') y1 = kwargs.get('y1') x2 = kwargs.get('x2') y2 = kwargs.get('y2') return ((x1-x2)** 2+(y1-y2)**2)** 0.5 x1,y1 = int(input('x1:')),int(input('y1:')) x2,y2 = int(input('x2:')),int(input('y2:')) print(distance(x1=x1,y1=y1,x2=x2,y2=y2))
1 2 3 4 5 6 7 8 9 10 11 12 13 # 3.面向对象编程:更高级、更抽象的一种模块化和封装 class Point: def __init__(self,a,b): self.x = a self.y = b def distance(self,p): return ((self.x-p.x)**2+(self.y-p.y)**2)**0.5 p1 = Point(0,0) p2 = Point(1,1) print(p1.distance(p2))
二、类和对象 1 2 3 4 5 1. 面向对象的设计思想是从自然界中来的(从现实世界中获取的),因为在自然界中,类(Class)和实例(Instance)的概念是很自然的2. Class(类型)是一种抽象的概念,比如我们定义一个Class - Person,是指人这个概念. 人是一个抽象的概念,不能具化。而实例指的就是一个一个的具体的人,比如:张三、李四、王五他们是具体某一个人,他们的类型是“人”。 人是张三、李四、王五的类型 而张三、李四、王五是一个个具体的实例
1、类到底是什么 1 2 3 4 5 6 1. 类是对客观世界中具有相同属性和行为的一组对象的抽象 人(类): 一类对象:张三、李四、王五 人:姓名、年龄、生日(属性).. 吃饭、睡觉(行为)等 类:人、狗、坐标中的点、帐户 对象:张三、旺财、(1,1)、620....
2、对象又是什么 1 2 3 4 5 1. 现实世界中客观存在的任何一个事务都可以看成是一个"对象",或者说,现实世界就是由千千万万个对象组成. 而这些对象是可以进行一个类别的划分. 2. 对象可以有形的,如一座房子、一个人、一辆车、一个学生等.它也可以是无形,如:银行帐户、一次旅行等3. 对象指类的一个个具体的实例(存在).
3、类和对象的关系 1 2 # 类和对象的关系总结为:类是对象的抽象类型,而对象则是类的具体实例 人是张三的类型,而张三是人的具体实例
问题:在编程世界中,先有类,还是先有对象
答:先有类,才有对象
三、如何进行面向对象的编程 1、定义类 一个类应该包含两部分:属性(变量)和行为(方法 - 函数)
1 2 3 4 5 6 7 8 9 10 class Person : name = 'Mr_lee' age = '18' def eat (self ): print ('是人就得吃饭' ) def sleep (self ): print ('人和猪都得睡觉' )
2、定义对象 1 2 3 4 5 6 7 8 9 p1 = Person() p2 = Person() print (p1.name) print (p2.name) p1.eat() p2.eat()
四、类属性和实例属性 1 2 3 1. 在上面的案例中,所有人的姓名和年龄都是一样的(属性的值是一样)2. 所有对象的所有的属性值都一样(类属性),对于姓名和年龄它是不合理的。
1、类属性
类内部定义的变量,不在任何的方法中
所有的对象都可以共用
可以使用类名.属性名访问,也可以使用对象名.属性名访问
一旦修改了类属性的值,所有的对象去访问时都会变. 为什么?
1 2 3 1. 每一个对象,都会在内存中占用一块空间,对象占用的空间实际上是它的属性占用的空间2. 如果是类属性,在整个类中只有一块空间,所有的对象都共享这块空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Student : teacher_name = 'Mr_lee' def print_teacher (self ): print (f"我是老师是:{self.teacher_name} " ) s1 = Student() s2 = Student() print (s1.teacher_name) print (s2.teacher_name) Student.teacher_name = 'Dr.lee' print (s1.teacher_name) print (s2.teacher_name)
注意 :
2、实例属性 当声明学生对象时,每一个学生都应该拥有自己的姓名、年龄等属性,这些属性在内存中应该独立存在,而不应该被共享。
1 2 3 4 5 6 7 8 class Student : name = 'Tom' age = 18 s1 = Student() s2 = Student()
此时,name和age应该被声明为实例属性。(属于某一个对象,而不是被所有对象共享)
如何声明实例属性 :
在类中的方法中进行声明,基本形式:self.xx = xx
,如果直接在方法中声明为xx=xx
,则这它是普通的局部变量
实例属性的生命周期是和对象的生命周期绑定
某一个对象的实例属性发生了改变,不会影响另外的对象
实例属性要使用** 对象名.属性名
**去访问
1 2 3 4 5 6 7 8 9 10 11 12 13 class Student : teacher_name = 'Mr_lee' def init_name (self, n ): self.name = n def output (self ): print (f'我的名字是{self.name} ,我的老师是{self.teacher_name} ' ) s1 = Student() s1.init_name('Tom' ) s1.output()
五、self参数和__init__
方法 1、self参数 1 2 3 4 5 1. 类中的实例方法 ,在定义时,都有一个默认的参数self (约定俗成)2. self是向方法的调用者,当某个对象在调用实例方法时,默认会将对象作为实参传递给方法,作为第一个参数,所以self就是指向对象本身,谁调用该方法self就指向谁 3. s1.init_name('Tom') self指向s1 或 self就是s1
2、__init__
方法 1 2 3 4 5 6 7 8 9 10 class Student : teacher_name = 'Mr_lee' def init_name (self, n ): self.name = n s1 = Student() print (s1.name)
期望,当声明完对象时,有一个方法可以自动被调用,而不需要程序员手动调用,在这个方法来完成实例属性的初始化
1 2 3 4 5 6 7 8 9 10 11 12 class Student : teacher_name = 'Mr_lee' def __init__ (self, n ): self.name = n s1 = Student('Tom' ) print (s1.name)s2 = Student('Jack' ) print (s2.name)
作用:初始化实例属性,__init__
方法是自动调用
__init__
方法可以加参数,因此在实例化对象从外界传递数据给实例属性
__init__
方法不能定义返回值,它应该返回None
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Point : def __init__ (self,x,y ): self.x = x self.y = y def output (self ): print (f'({self.x} ,{self.y} )' ) p = Point(0 ,0 ) p.output() p2 = Point(y=2 ,x=1 ) p2.output()
六、组合类 把一个类的对象,作为另一个类的成员(属性)
1 2 3 4 5 6 7 8 9 10 11 12 class Circle : def __init__ (self,x,y,r ): self.x = x self.y = y self.radius = r def print_circle (self ): print (self.x,self.y,self.radius) c = Circle(1 ,2 ,3 ) c.print_circle()
修改成组合类形式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Point : def __init__ (self,x,y ): self.x = x self.y = y def distance (self,p ): return ((self.x-p.x)**2 +(self.y-p.y)**2 )**0.5 def output (self ): print (f'({self.x} ,{self.y} )' ) class Circle : def __init__ (self,x,y,r ): self.radius = r self.center = Point(x,y) def output (self ): print (self.radius,self.center.x,self.center.y) def distance (self,c ): dis = self.center.distance(c.center) return dis c1 = Circle(1 ,2 ,3 ) c1.output() print (c1.distance(c2))
七、访问限制 权限:公有、保护、私有
面向对象的三大特性:封装、继承、多态
封装:
将对象的属性和方法进行有机的结合,形成一个整体(包装起来)
将不想暴露在外界的成员进行私有化,外界无法直接访问,只能在类中提供公有的接口(公有方法)来供外界去访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Student : def __init__ (self,n,a ): self.__name = n self.__age = a def output (self ): print (self.__name,self.__age) s1 = Student('Mr_lee' ,18 ) s1.output() print (s1.__name)
公有 :属性名前没有__,在类内部及类外都可以直接通过对象名.属性名访问
保护 :_名字
私有 (伪私有):属性名前加__名字
,此时可以在类内部通过 self.__属性名
来访问,但不可以在类外通过对象名来进行访问
语法:双下划线+名字 私有属性
范围:只能在本类中访问
访问:通过get、set等公有方法来访问和修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Student : def __init__ (self,n,a ): self.__name = n self.__age = a def get_name (self ): return self.__name def set_name (self,n ): self.__name = n def output (self ): print (self.__name,self.__age) s1 = Student('Mr_lee' ,18 ) s1.output() print (s1.get_name()) s1.set_name('Jack' )
根本原因:在外界访问不到__name
私有属性,是因为Python对于__name
声明的属性进行了重命名操作。_类名__属性名
1 print (s1._Student__name)